class Watch{
    constructor(vm,key,node,nodeAttr){
        this.vm = vm;
        this.key = key;
        this.node = node;
        this.nodeAttr = nodeAttr;

        this.update();
    }

    update(){
        this.node[this.nodeAttr] = this.vm[this.key];
    }
}

class Vue{
    constructor(options){
        this.$options = options;
        this.$watchEvents = {};

        if(toString.call(options.beforeCreate) === '[object Function]'){
            options.beforeCreate.call(this);
        }

        this.$data = options.data;

        this.Proxy();

        if(toString.call(options.created) === '[object Function]'){
            options.created.call(this);
        }

        this.$el = document.querySelector(options.el);

        this.complite(this.$el);

        if(toString.call(options.beforeMount) === '[object Function]'){
            options.beforeMount.call(this);
        }

        if(toString.call(options.mounted) === '[object Function]'){
            options.mounted.call(this);
        }
    }

    Proxy(){
        Object.keys(this.$data).forEach(key=>{
            Object.defineProperty(this,key,{
                get(){
                    return this.$data[key];
                },
                set(value){
                    this.$data[key] = value;

                    if(this.$watchEvents.hasOwnProperty(key)){
                        this.$watchEvents[key].forEach(watcher=>{
                            watcher.update();
                        })
                    }
                }
            });
        })
    }

    complite(el){
        el.childNodes.forEach(node=>{
            // 判断是否是元素节点
            if(node.nodeType === 1){
                // 判断元素节点是否绑定了@click事件
                if(node.hasAttribute('@click')){
                    let eventName = node.getAttribute('@click');
                    node.addEventListener('click',(...args)=>{
                        this.$options.methods[eventName].apply(this,args);
                    });
                }

                // 判断元素节点是否绑定了v-model
                if(node.hasAttribute('v-model')){
                    let key = node.getAttribute('v-model');

                    if(this.hasOwnProperty(key)){
                        node.value = this[key]; 
                    }

                    node.addEventListener('input',(e)=>{
                        this[key] = e.target.value;
                    })
                }

                this.complite(node);
            }

            // 判断是否是文本节点
            if(node.nodeType === 3){
                let reg = /\{\{(.*?)\}\}/g;
                let content = node.textContent;

                node.textContent = content.replace(reg,(match,key)=>{
                    key = key.trim();

                    if(this.hasOwnProperty(key)){
                        let watcher = new Watch(this,key,node,'textContent');

                        if(this.$watchEvents.hasOwnProperty(key)){
                            this.$watchEvents[key].push(watcher);
                        }else{
                            this.$watchEvents[key] = [watcher];
                        }
                    }

                    return this.$data[key];
                })
            }
        })
    }
}

new Vue({
    el:'#app',
    data:{
        name:'张三',
        content: '测试的内容'
    },
    beforeCreate(){
        console.log('beforeCreate');
    },
    created(){
        console.log('created');
    },
    beforeMount(){
        console.log('beforeMount');
    },
    mounted(){
        console.log('mounted');
    },
    methods:{
        change(e){
            this.name= '李四';
        }
    }
})

